import copy
import json
from typing import List
from typing import Union
from apis import api_routes
from flask import abort, g, request, jsonify
from security.decoration import certification
from models.product.routes import Routes
from models.facility.facility import Facility
from security.security import decode_jwt
from public.local import datetime_type
from models.users.users import Users
from models.product.aircraft import Aircraft
from public.contexts import context_logs


@api_routes.route("/routes", methods=["POST"])
@certification(auth=True, role=None)
def func_routes_post_api():
    """
    添加工艺路径，完成API开发
    http://127.0.0.1:8080/api/routes
    Content-Type=application/json
    methods=["POST"]
    {
    "name"          string      ****    工艺路线名称
    "routes"        array[json] ****    生产加工工艺路线  [{"ft_ids": [1]}, {"ft_ids": [2, 3]},{"ft_ids": [4]}, ....]
    :return:
        {'status': 400, 'msg': '客户端发送请求异常'}
        {'status': 4000, 'msg': "名称已存在，禁止重复添加"}
        {'status': 4001, 'msg': "工序参数数据类型类型错误"}
        {'status': 4002, 'msg': "工序参数验证设备不能为空"}
        {'status': 4003, 'msg': "工序参数没有找到要绑定设备"}
        {'status': 4004, 'msg': "设备没有绑定PLC, 无法交互，禁止添加"}
        {'status': 4005, 'msg': "同一工序禁止添加重复设备"}
        {'status': 4006, 'msg': "相隔工序不能存在同一种设备"}
        {'status': 200, 'msg': "添加工艺路线成功"}
    ---
    tags:
      - 生产工艺管理
    """

    data: dict = request.get_json()
    name: str = data.get("name")
    routes: list = data.get("routes")

    if not all([name]):
        abort(400)
    if not isinstance(routes, list):
        abort(400)
    db_route: Union[Routes, None] = g.session.query(Routes).filter(Routes.name == name).first()
    if db_route is not None:
        return jsonify({'status': 4000, 'msg': "名称已存在，禁止重复添加"})

    # 解析routes数据，判断是否合法性
    temp_routes: list = []
    for index, itr in enumerate(routes):
        if (not isinstance(itr, dict)) or (not isinstance(itr.get("ft_ids"), list)):
            return jsonify({'status': 4001, 'msg': "工序参数数据类型类型错误"})
        ft_ids: list = itr.get("ft_ids")
        if len(ft_ids) == 0:
            return jsonify({'status': 4002, 'msg': "工序参数验证设备不能为空"})
        for itr2 in ft_ids:
            db_ft: Union[Facility, None] = g.session.query(Facility).filter(Facility.id == itr2).first()
            if db_ft is None:
                return jsonify({'status': 4003, 'msg': "工序参数没有找到要绑定设备"})
            if db_ft.uuid4 is None:
                return jsonify({'status': 4004, 'msg': "设备没有绑定PLC, 无法交互，禁止添加"})
        if len(set(ft_ids)) != len(ft_ids):
            return jsonify({'status': 4005, 'msg': "同一工序禁止添加重复设备"})
        temp_routes.append(ft_ids)

    for itr in range(1, len(temp_routes)):
        before: list = temp_routes[itr - 1]
        now_date: list = temp_routes[itr]
        list3 = []
        for item in before:
            if item in now_date:
                list3.append(item)
        if len(list3) != 0:
            return jsonify({'status': 4006, 'msg': "相隔工序不能存在同一种设备"})

    user_id: int = decode_jwt(g.token)["user_id"]
    g.session.add(Routes(
        name=name, route=json.dumps({"data": routes}),
        user_id=user_id, time=datetime_type()
    ))

    context_logs(name="新增工艺路径", obsolescence=None, data=json.dumps(data))

    g.session.commit()
    return jsonify({'status': 200, 'msg': "添加工艺路线成功"})


@api_routes.route("/routes/aircraft", methods=["GET"])
@certification(auth=True, role=None)
def func_routes_aircraft_get_api():
    """
    查询工艺路径全部名称，完成API开发
    http://127.0.0.1:8080/api/routes/aircraft
    Content-Type=application/x-www-form-urlencoded
    methods=["GET"]
    {
    }
    :return:
        {'status': 200, 'data': data }
    ---
    tags:
      - 生产工艺管理
    """
    db_data: List[Routes] = g.session.query(Routes).order_by(Routes.id).all()
    resp = []
    for itr in db_data:
        resp.append({
            "key": itr.id,
            "value":  itr.name
        })

    return jsonify({'status': 200, 'data': resp})


@api_routes.route("/routes", methods=["GET"])
@certification(auth=True, role=None)
def func_routes_get_api():
    """
    查询工艺路线详细信息，完成API开发
    http://127.0.0.1:8080/api/routes
    Content-Type=application/x-www-form-urlencoded
    methods=["GET"]
    {
    "index"     int      ****  第几页，默认为1
    "size"      int      ****  每页数据多少, 默认每页10条数据
    }
    :return:
        {'status': 400, 'msg': '客户端发送请求异常'}
        {'status': 4000, 'msg': "没有找到要跟新数据源"}
        {'status': 4001, 'msg': "非阿拉伯数据类型无法更新"}
        {'status': 200, 'msg': "修改参数成功", }
    ---
    tags:
      - 生产工艺管理
    """
    index = request.args.get("index", default=1, type=int)
    size = request.args.get("size", default=10, type=int)

    count: int = g.session.query(Routes).order_by(Routes.id).count()
    page: int = int((count / size) + 1) if (count / size) > int(count / size) else int(count / size)
    db_data: List[Routes] = g.session.query(Routes).order_by(Routes.id).offset((index - 1) * size).limit(size).all()

    resp: list = []
    for index, itr in enumerate(db_data):

        list_rts: list = []
        route: dict = json.loads(itr.route)
        routes: list = route.get("data")
        for sequence, rts in enumerate(routes):
            data_rts: list = []
            data_rts.clear()
            db_rout: list = rts.get("ft_ids")
            for _, rt in enumerate(db_rout):
                db_ft: Facility = g.session.query(Facility).filter(Facility.id == rt).first()
                data_rts.append({
                    "facility_id": db_ft.id,
                    "sequence": sequence + 1,
                    "serials": db_ft.serials,
                    "name": db_ft.name
                })
            list_rts.append(data_rts)
        db_users: Users = g.session.query(Users).filter(Users.id == itr.user_id).first()

        resp.append({
            "route_id": itr.id,
            "name": itr.name,
            "routes": copy.deepcopy(list_rts),
            "user_name": db_users.name,
            "time": itr.time.strftime("%Y-%m-%d %H:%M:%S") if itr.time else None
        })
    doc: dict = {
        "route_id": "对应数据库ID",
        "name": "工艺路线名字",
        "user_name": "谁添加此工艺路径",
        "time": "路径添加时间",
        "routes": [{
            "sequence": "加工顺序",
            "facility_id": "设备ID(对应数据库)",
            "name": "设备名称",
            "serials": "设备编码",
        }]
    }
    return jsonify({'status': 200, 'data': resp, "index": index, "size": size, "total": count, "pages": page, "doc": doc})


@api_routes.route("/routes", methods=["PUT"])
@certification(auth=True, role=None)
def func_routes_put_api():
    """
    更新工艺路线详细信息, 完成API开发
    http://127.0.0.1:8080/api/routes
    Content-Type=application/json
    methods=["PUT"]
    {
    "route_id"      int         ****    对应路劲数据库ID
    "name"          string      ****    路线名字
    "routes"        array[json] ****    生产加工工艺路线  [{"ft_ids": [1]}, {"ft_ids": [2, 3]},{"ft_ids": [4]}, ....]
    }
    :return:
        {'status': 4000, 'msg': "没有找到路径工艺"}
        {'status': 4001, 'msg': "工艺名字已存在，禁止修改"}
        {'status': 4002, 'msg': "生产加工路径参数错误"}
        {'status': 4003, 'msg': "工序参数没有找到要绑定设备"}
        {'status': 4004, 'msg': "设备没有绑定PLC, 无法交互"}
    ---
    tags:
      - 生产工艺管理
    """
    data: dict = request.get_json()
    route_id: int = data.get("route_id")
    name: str = data.get("name")
    routes: list = data.get("routes")

    if not route_id:
        abort(400)
    db_route: Union[Routes, None] = g.session.query(Routes).filter(Routes.id == route_id).first()
    if not db_route:
        return jsonify({'status': 4000, 'msg': "没有找到路径工艺"})

    context_logs(name="工艺路径数据更新", obsolescence=db_route.__repr__(), data=json.dumps(data))

    if name != db_route.name and name is not None:
        route0: Union[Routes, None] = g.session.query(Routes).filter(Routes.name == name).first()
        if route0 is not None:
            return jsonify({'status': 4001, 'msg': "工艺名字已存在，禁止修改"})
        db_route.name = name

    if routes is not None:
        temp_routes: list = []
        if not isinstance(routes, list):
            g.session.rollback()
            return jsonify({'status': 4002, 'msg': "生产加工路径参数错误"})

        for _, itr in enumerate(routes):
            if (not isinstance(itr, dict)) or (not isinstance(itr.get("ft_ids"), list)):
                return jsonify({'status': 4001, 'msg': "工序参数数据类型类型错误"})
            ft_ids: list = itr.get("ft_ids")
            if len(ft_ids) == 0:
                return jsonify({'status': 4002, 'msg': "工序参数验证设备不能为空值"})

            for itr2 in ft_ids:
                db_ft: Union[Facility, None] = g.session.query(Facility).filter(Facility.id == itr2).first()
                if db_ft is None:
                    return jsonify({'status': 4003, 'msg': "工序参数没有找到要绑定设备"})
                if db_ft.uuid4 is None:
                    return jsonify({'status': 4004, 'msg': "设备没有绑定PLC, 无法交互"})
            if len(set(ft_ids)) != len(ft_ids):
                return jsonify({'status': 4005, 'msg': "同一工序禁止添加重复设备"})
            temp_routes.append(ft_ids)

        for itr in range(1, len(temp_routes)):
            before: list = temp_routes[itr - 1]
            now_date: list = temp_routes[itr]
            list3 = []
            for item in before:
                if item in now_date:
                    list3.append(item)
            if len(list3) != 0:
                return jsonify({'status': 4006, 'msg': "相隔工序不能存在同一种设备！"})
        db_route.route = json.dumps({"data": routes})

    g.session.commit()
    return jsonify({'status': 200, 'msg': "更新产品工艺路径信息成功"})


@api_routes.route("/routes/start", methods=["POST"])
@certification(auth=True, role=None)
def func_routes_start_post_api():
    """
    下发生产配方指令给PLC
    http://127.0.0.1:8080/api/routes/start
    Content-Type=application/json
    methods=["POST"]
    {
    "name"      string     ****    工位名称
    "serial"    string     ****    工位编号
    "enable"    int(1或者0) ****    是否在看板展示
    }
    :return:
        {'status': 400, 'msg': '客户端发送请求异常'}
        {'status': 403, 'msg': "token无效或者未登录或没有权限"}
        {'status': 4000, 'msg': "已经存在此用户"}
        {'status': 200, 'msg': "添加账户成功", }
    ---
    tags:
      - 生产工艺管理
    """
    data: dict = request.get_json()
    route_id: int = data.get("route_id")

    if route_id is None:
        abort(400)

    return jsonify({'status': 200, 'msg': "写入配方成功"})


@api_routes.route("/routes/stop", methods=["POST"])
@certification(auth=True, role=None)
def func_routes_stop_post_api():
    """
    下发停止指令给PLC
    http://127.0.0.1:8080/api/routes/write
    Content-Type=application/json
    methods=["POST"]
    {
    "name"      string     ****    工位名称
    "serial"    string     ****    工位编号
    "enable"    int(1或者0) ****    是否在看板展示
    }
    :return:
        {'status': 400, 'msg': '客户端发送请求异常'}
        {'status': 403, 'msg': "token无效或者未登录或没有权限"}
        {'status': 4000, 'msg': "已经存在此用户"}
        {'status': 200, 'msg': "添加账户成功", }
    ---
    tags:
      - 生产工艺管理
    """
    data: dict = request.get_json()
    route_id: int = data.get("route_id")
    if not route_id:
        abort(400)

    return jsonify({'status': 200, 'msg': "暂停指令写入成功"})


@api_routes.route("/routes", methods=["DELETE"])
@certification(auth=True, role=None)
def func_routes_delete_api():
    """
    删除工艺路径， 前端最好做一个提示，谨慎删除
    http://127.0.0.1:8080/api/routes
    Content-Type=application/json
    methods=["DELETE"]
    {
    "route_id"      int     ****    对应路劲数据库ID
    }
    :return:
        {'status': 4000, 'msg': "没有找到路径工艺"}
        {'status': 4001, 'msg': "已绑定产品，无法删除，先删除产品"}
        {'status': 200, 'msg': "删除成功"}
    ---
    tags:
      - 生产工艺管理
    """
    data: dict = request.get_json()
    route_id: int = data.get("route_id")
    if not route_id:
        abort(400)

    db_route: Union[Routes, None] = g.session.query(Routes).filter(Routes.id == route_id).first()
    if db_route is None:
        return jsonify({'status': 4000, 'msg': "没有找到路径工艺"})

    context_logs(name="工艺路径数据删除", obsolescence=db_route.__repr__(), data=json.dumps(data))

    db_aircraft: Union[Aircraft, None] = g.session.query(Aircraft).filter(Aircraft.route_id == route_id).first()
    if db_aircraft is not None:
        return jsonify({'status': 4001, 'msg': "已绑定产品，无法删除，先删除产品"})

    g.session.query(Routes).filter(Routes.id == route_id).delete()
    g.session.commit()

    return jsonify({'status': 200, 'msg': "删除成功"})
